import os.path
import random
import re
import time

from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q
from django.http import FileResponse
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.throttling import AnonRateThrottle
from rest_framework.viewsets import GenericViewSet
from rest_framework_simplejwt.exceptions import TokenError, InvalidToken
from rest_framework_simplejwt.views import TokenObtainPairView
from rest_framework.views import APIView
from rest_framework import status, mixins

from common.aliyun_message import AliyunSMS
from config.default import MEDIA_ROOT
from users.models import User, VerifCode
from .permissions import UserPermission
from .serializers import UserSerializer
from rest_framework.permissions import IsAuthenticated

# Create your views here.
class RegisterView(APIView):
    """用户注册"""
    def post(self, request):
        # 一.接收用户参数
        username = request.data.get('username')
        password = request.data.get('password')
        # email = request.data.get('email')
        password_confirmation = request.data.get('password_confirmation')

        # 二.参数校验
        # 1.校验参数是否为空
        if not all([username, password, password_confirmation]):
            return Response({'code': '1001', 'message': '参数不能为空'}, status=status.HTTP_200_OK)
        # 2.校验用户名是否已注册
        if User.objects.filter(username=username).exists():
            return Response({'code': '1002', 'message': '用户名已注册'}, status=status.HTTP_200_OK)
        # 3.校验两次密码是否一致
        if password != password_confirmation:
            return Response({'code': '1004', 'message': '两次密码长度不一致'}, status=status.HTTP_200_OK)
        # 4. 校验密码长度
        if not (6 <= len(password) <= 18):
            return Response({'code': '1003', 'message': '密码长度应在6-18位之间'}, status=status.HTTP_200_OK)
        # # 5.校验邮箱是否存在
        # if User.objects.filter(email=email).exists():
        #     return Response({'code': '422', 'message': '该邮箱已被其他用户使用'}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        # # # 6.校验邮箱格式是否正确
        # if not re.match(r'^[a-zA-Z0-9_+&*-]+(?:\\.[a-zA-Z0-9_+&*-]+)*@(?:[a-zA-Z0-9-]+\\.)+[a-zA-Z]{2,7}$', email):
        #     return Response({'code': '422', 'message': '邮箱格式不正确'},status=status.HTTP_422_UNPROCESSABLE_ENTITY)

        # 三.创建用户
        obj = User.objects.create_user(username=username, password=password)
        res = {
            "code": "1000",
            "message": "注册成功",
            "data":{
                'id': obj.id,
                "username": obj.username,
            }
        }
        return Response(res, status=status.HTTP_200_OK)

class LoginView(APIView):
    """用户登录"""
    def post(self, request, *args, **kwargs):
        """登录"""
        username = request.data.get("username")
        password = request.data.get("password")

        try:
            user = User.objects.get(Q(username=username) | Q(mobile=username) | Q(email=username))
        except ObjectDoesNotExist:
            return Response({"code": "1001", "msg": "没有找到用户"}, status=status.HTTP_200_OK)
        else:
            if user.check_password(password):
                data = {
                    'id': user.id,
                    "username": user.username,
                    "mobile": user.mobile,
                    "email": user.email
                }
                return Response({"code": "1000", "msg": "登录成功", "data": data}, status=status.HTTP_200_OK)
            else:
                return Response({'code': "1002", 'message': "密码错误"}, status=status.HTTP_200_OK)

class UserView(GenericViewSet, mixins.RetrieveModelMixin):
    """用户操作相关的视图集"""
    queryset = User.objects.all()
    serializer_class = UserSerializer
    # 设置认证用户才能有权限访问
    # permission_classes = [IsAuthenticated, UserPermission]

    def upload_avatar(self, request, *args, **kwargs):
        """上传用户头像"""
        avatar = request.data.get('avatar')
        # 校验是否有上传文件
        if not avatar:
            return Response({'code': "1001", 'message': "文件不能为空"}, status=status.HTTP_200_OK)
        # # 校验文件大小不能超过300kb
        # if avatar.size > 1024*300:
        #     return Response({'code': "1002", 'error': "文件大小不能超过300kb"}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        # 二.保存文件
        # 1.获取用户信息
        user = self.get_object()
        # 2.获取序列化对象,partial=True只对部分进行函数校验
        ser = self.get_serializer(user, data={"avatar": avatar}, partial=True)
        # 3.校验
        ser.is_valid(raise_exception=True)
        ser.save()
        return Response({"code": "1000", "message": "上传头像成功", "data": {'url': ser.data['avatar']}}, status=status.HTTP_200_OK)

    @staticmethod
    def verif_code(code, codeID, mobile):
        """
        校验验证码通用逻辑
        :param code: 验证码
        :param codeID: 验证码id
        :param mobile: 手机号
        :return:验证通过返回Node,否则返回Response
        """
        # 1.校验参数是否为空
        if not code:
            return {"code": "1101", "message": "验证码不能为空"}
        if not codeID:
            return {"code": "1102", "message": "验证码id不能为空"}
        if not mobile:
            return {"code": "1103", "message": "手机号不能为空"}
        # 校验验证码是否正确
        if VerifCode.objects.filter(id=codeID, code=code, mobile=mobile).exists():
            # 校验验证码是否过期：过期时间1分钟
            c_obj = VerifCode.objects.get(id=codeID, code=code, mobile=mobile)
            # 获取验证码的创建时间的时间戳
            ct = c_obj.create_time.timestamp()
            # 获取当前时间的时间戳
            et = time.time()
            # 删除验证码，避免出现用户在验证码有效期内使用同一个验证码重复请求
            c_obj.delete()
            # 是否超时
            if ct + 600 < et:
                return {"code": "1104", "message": "验证码已过期"}
        else:
            return {"code": "1105", "message": "验证码不正确"}

    def bind_mobile(self, request, *args, **kwargs):
        """绑定手机号"""
        # 1.获取参数
        code = request.data.get('code')
        codeID = request.data.get('codeID')
        mobile = request.data.get('mobile')
        # # 2.校验参数
        # if not code:
        #     return Response({"code": "422", "message": "验证码不能为空"}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        # if not codeID:
        #     return Response({"code": "422", "message": "验证码id不能为空"}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        # if not mobile:
        #     return Response({"code": "422", "message": "手机号不能为空"}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)
        # # 校验验证码是否正确
        # if VerifCode.objects.filter(id=codeID, code=code, mobile=mobile).exists():
        #     # 校验验证码是否过期：过期时间1分钟
        #     c_obj = VerifCode.objects.get(id=codeID, code=code, mobile=mobile)
        #     # 获取验证码的创建时间的时间戳
        #     ct = c_obj.create_time.timestamp()
        #     # 获取当前时间的时间戳
        #     et = time.time()
        #     # 删除验证码，避免出现用户在验证码有效期内使用同一个验证码重复请求
        #     c_obj.delete()
        #     # 是否超时
        #     if ct + 60 < et:
        #         return Response({"code": "422", "message": "验证码已过期"}, status=status.HTTP_422_UNPROCESSABLE_ENTITY)

        # 2.校验验证码
        result = self.verif_code(code, codeID, mobile)
        if result:
            return Response(result,status=status.HTTP_200_OK)
        # 校验手机号
        if User.objects.filter(mobile=mobile).exists():
            return Response({"code": "1001", "message": "该手机号已被用户绑定"}, status=status.HTTP_200_OK)
        # 绑定手机号
        user = self.get_object()
        user.mobile = mobile
        user.save()
        return Response({"code": "1000", "message": "手机绑定成功"}, status=status.HTTP_200_OK)

    def unbind_mobile(self, request, *args, **kwargs):
        """解绑手机号"""
        # 1.获取参数
        code = request.data.get('code')
        codeID = request.data.get('codeID')
        mobile = request.data.get('mobile')
        # 2.校验验证码
        result = self.verif_code(code, codeID, mobile)
        if result:
            return result
        # 3.解绑手机
        user = self.get_object()
        if user.mobile == mobile:
            user.mobile = ''
            user.save()
            return Response({"code": "1000", "message": "解绑成功"},status=status.HTTP_200_OK)
        else:
            return Response({"code": "1001", "message": "当前用户绑定的不是该号码"},status=status.HTTP_200_OK)

    def update_name(self,request, *args, **kwargs):
        """用户昵称修改"""
        # 获取参数
        last_name = request.data.get('last_name')

        # 校验参数
        if not last_name:
            return Response({'code': "1001", "message": "参数last_name不能为空"}, status=status.HTTP_200_OK)

        # 修改用户名
        user = self.get_object()
        user.last_name = last_name
        user.save()
        return Response({"code": "1000", 'message': "修改昵称成功", "last_name": last_name}, status=status.HTTP_200_OK)

    def update_password(self,request, *args, **kwargs):
        """修改用户密码"""
        # 1.获取参数
        password = request.data.get("password")
        new_password = request.data.get("new_password")
        password_confirmation = request.data.get("password_confirmation")

        # 2.校验密码
        if not password:
            return Response({"code": "1001", "message": "原密码不能为空"}, status=status.HTTP_200_OK)
        if not new_password:
            return Response({"code": "1002", "message": "新密码不能为空"}, status=status.HTTP_200_OK)
        if not password_confirmation:
            return Response({"code": "1003", "message": "确认密码不能为空"}, status=status.HTTP_200_OK)

        user = self.get_object()
        if not user.check_password(password):
            return Response({"code": "1004", "message": "原密码不正确"}, status=status.HTTP_200_OK)
        if new_password != password_confirmation:
            return Response({"code": "1005", "message": "确认密码和新密码不一致"}, status=status.HTTP_200_OK)

        # 3.修改密码--修改密码必须使用set_password方法
        user.set_password(new_password)
        user.save()
        return Response({"code": "1000", "message": "修改密码成功"}, status=status.HTTP_200_OK)

    def bind_email(self, request, *args, **kwargs):
        """绑定邮箱"""
        # 1.获取参数
        email = request.data.get('email')
        # 2.校验参数
        if not email:
            return Response({"code": "1001", "message": "邮箱输入为空"},
                            status=status.HTTP_200_OK)
        res = re.match(r'[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$', email)
        if not res:
            return Response({"code": "1002", "message": "邮箱格式不正确"},
                            status=status.HTTP_200_OK)
        # 绑定邮箱
        user = self.get_object()
        user.email = email
        user.save()
        return Response({"code": "1000", "message": "邮箱绑定成功", "email": email}, status=status.HTTP_200_OK)

class FileView(APIView):
    """获取文件的视图"""
    def get(self, request, name):
        path = MEDIA_ROOT / name
        if os.path.isfile(path):
            return FileResponse(open(path, 'rb'))
        return Response({"code": "1001", "message": "文件不存在"}, status=status.HTTP_200_OK)

class SMSView(APIView):
    """短信验证码发送"""
    throttle_classes = [AnonRateThrottle,]

    def post(self, request):
        # 获取手机号
        mobile = request.data.get('mobile')
        # 校验手机号是否为空
        if not mobile:
            return Response({"code": "1001", 'error': "手机号为空"}, status=status.HTTP_200_OK)
        # 验证手机号码格式是否正确（正则表达式匹配）
        res = re.match(r'^1[3456789]\d{9}$', mobile)
        if not res:
            return Response({"code": "1002", 'error': "无效的手机号"}, status=status.HTTP_200_OK)
        # 发送短信验证码
        code = self.get_random_code()
        result = AliyunSMS().send(mobile=mobile, code=code)
        if result['code'] == '1000':
            # 将验证码入库
            obj = VerifCode.objects.create(mobile=mobile, code=code)
            result['codeID'] = obj.id
            return Response(result, status=status.HTTP_200_OK)
        else:
            return Response(result, status=status.HTTP_200_OK)

    @staticmethod
    def get_random_code():
        """获得6为随机的验证码"""
        return ''.join([str(random.choice(range(10))) for i in range(6)])
